package com.em.sugarfight.service.engine;

import com.em.sugarfight.entity.*;
import com.em.sugarfight.sugarEnums.*;
import com.em.sugarfight.util.AdjustPositionUtil;
import com.em.sugarfight.util.CoordinateConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 炸弹决策整合器 - 将炸弹策略与移动决策整合
 */
@Component
public class CombinedStrategyEngine {

    private static final Logger logger = LoggerFactory.getLogger(CombinedStrategyEngine.class);

    private static FixedSizeContainer<PixelPosition> positions = new FixedSizeContainer<>(1);

    @Autowired
    private MovementDecisionEngine movementEngine;
    @Autowired
    private BombStrategyEngine bombEngine;

    public CombinedStrategyEngine() {
        this.movementEngine = new MovementDecisionEngine();
        this.bombEngine = new BombStrategyEngine();
    }

    /**
     * 综合决策 - 同时考虑移动和炸弹策略
     */
    public MoveCommand makeDecision(GameState gameState) {
        // 1. 计算危险地图
        DangerMap dangerMap = calculateDangerMap(gameState);
        PixelPosition position = gameState.getMy_player().getPosition();
        if(positions.contains(position) && AdjustPositionUtil.needToAdjust(gameState, position)){
            return AdjustPositionUtil.adjustMyPosition(gameState,dangerMap);
        }
        positions.add(position);
        logger.info("当前像素位置:{}",gameState.getMy_player().getPosition());

        // 2. 炸弹决策
        boolean shouldPlaceBomb = bombEngine.shouldPlaceBomb(gameState);

        // 3. 移动决策
        MoveCommand moveCommand;
        if (shouldPlaceBomb) {
            logger.info("放置炸弹并移动");
            // 如果要放炸弹，优先考虑炸弹后的移动策略
            moveCommand = decideBombAndMove(gameState, dangerMap);
        } else {
            logger.info("普通移动");
            // 普通移动决策
            moveCommand = movementEngine.decideMovement(gameState,dangerMap);
        }

//        if(moveCommand.getIs_place_bomb()) {
//            return new MoveCommand(moveCommand.getDirection(), true, 0);
//        }
//        else
//            return new MoveCommand(moveCommand.getDirection(), false, moveCommand.getStride());
        return moveCommand;
    }

    /**
     * 炸弹+移动组合决策
     */
    private MoveCommand decideBombAndMove(GameState gameState, DangerMap dangerMap) {
        PlayerStateVo myPlayer = gameState.getMy_player();
        Position currentPos = CoordinateConverter.pixelToGrid(myPlayer.getPosition());
        logger.info("放置炸弹在:x={},y={}",currentPos.getX(),currentPos.getY());

        // 检查是否应该移动到更好的炸弹位置
//        Position bestBombPos = bombEngine.getBestBombPosition(gameState, dangerMap);
//
//        if (!currentPos.equals(bestBombPos)) {
//            // 需要先移动到最佳炸弹位置
//            return moveToBombPosition(bestBombPos, gameState, dangerMap);
//        } else {
//            // 当前位置就是最佳位置，放炸弹后立即逃离
        return planEscapeRoute(currentPos, gameState, dangerMap);
//        }
    }

    /**
     * 移动到炸弹位置
     */
//    private MoveCommand moveToBombPosition(Position targetPos, GameState gameState, DangerMap dangerMap) {
//        Position currentPos = CoordinateConverter.pixelToGrid(gameState.getMy_player().getPosition());
//        Direction direction = getDirectionTo(currentPos, targetPos);
//
//        return new MoveCommand(direction.toString(), false, 0);
//    }

    /**
     * 规划逃生路线
     */
    private MoveCommand planEscapeRoute(Position bombPos, GameState gameState, DangerMap dangerMap) {
        // 模拟放炸弹后的危险情况
        DangerMap futureMap = simulateBombPlacement(bombPos, gameState, dangerMap);
        logger.info("放置炸弹后的为县地图:{}",dangerMap);

        // 寻找最近的安全位置
        Position safePos = findNearestSafePosition(bombPos, futureMap, gameState);
        logger.info("found safePos:{}",safePos);

        if (safePos != null) {
            Direction escapeDirection = getDirectionTo(bombPos, safePos);
            return new MoveCommand(escapeDirection.toString(), true, 0); // 全速逃离
        }

        // 如果找不到安全位置，至少远离炸弹中心
        Direction awayDirection = getDirectionAwayFromDanger(bombPos, futureMap, gameState);
        return new MoveCommand(awayDirection.toString(), true, 0);
    }

    /**
     * 寻找最近的安全位置
     */
    public Position findNearestSafePosition(Position start, DangerMap dangerMap, GameState gameState) {
        Queue<Position> queue = new LinkedList<>();
        Set<Position> visited = new HashSet<>();

        queue.offer(start);
        visited.add(start);

        while (!queue.isEmpty()) {
            Position current = queue.poll();
//            logger.info("寻找安全位置，当前位置:{}",current);

            if (isValidPosition(current,gameState) && !dangerMap.isInDanger(current) && !current.equals(start)) {
                return current; // 找到安全位置
            }

            // 搜索相邻位置
            for (Direction dir : Arrays.asList(Direction.U, Direction.D, Direction.L, Direction.R)) {
                Position next = current.move(dir);

                if (isValidPosition(next, gameState) && !visited.contains(next)) {
                    visited.add(next);
                    queue.offer(next);
                }
            }
        }

        return null; // 没找到安全位置
    }

    /**
     * 获取远离危险的方向
     */
    private Direction getDirectionAwayFromDanger(Position pos, DangerMap dangerMap, GameState gameState) {
        Direction bestDirection = Direction.U;
        double minDanger = Double.MAX_VALUE;

        for (Direction dir : Arrays.asList(Direction.U, Direction.D, Direction.L, Direction.R)) {
            Position nextPos = pos.move(dir);

            if (isValidPosition(nextPos, gameState)) {
                double danger = dangerMap.getRiskLevel(nextPos);
                if (danger < minDanger) {
                    minDanger = danger;
                    bestDirection = dir;
                }
            }
        }

        return bestDirection;
    }

    // ============ 辅助方法 ============

    private DangerMap calculateDangerMap(GameState gameState) {
        DangerMap dangerMap = new DangerMap(gameState.getMapWidth(), gameState.getMapHeight());

        // 标记现有炸弹威胁
        for (Bomb bomb : gameState.getBombs()) {
            dangerMap.markBombDanger(bomb,gameState.getCurrent_tick());
        }

        // 标记敌人潜在威胁
        for (PlayerStateVo enemy : getEnemies(gameState)) {
            if (enemy.getBomb_pack_count() > 0) {
                dangerMap.markPotentialBombZones(enemy);
            }
        }

        return dangerMap;
    }

    private DangerMap simulateBombPlacement(Position bombPos, GameState gameState, DangerMap currentMap) {
        // 这里应该调用 BombStrategyEngine 的方法
        currentMap.markBombDanger(new Bomb(bombPos,gameState.getMy_player().getId(),gameState.getMy_player().getTeam(),gameState.getMy_player().getSweet_potion_count(), gameState.getCurrent_tick()+20), gameState.getCurrent_tick());
        // 暂时用简化实现
        return currentMap;
    }

    public Direction getDirectionTo(Position from, Position to) {
        int dx = to.getX() - from.getX();
        int dy = to.getY() - from.getY();

        if (Math.abs(dx) > Math.abs(dy)) {
            return dx > 0 ? Direction.R : Direction.L;
        } else if (dy != 0) {
            return dy > 0 ? Direction.U : Direction.D;
        }

        return Direction.N;
    }

    private List<PlayerStateVo> getEnemies(GameState gameState) {
        List<PlayerStateVo> enemies = new ArrayList<>();
        String myTeam = gameState.getMy_player().getTeam().name();

        for (PlayerStateVo player : gameState.getOther_players()) {
            if (!player.getTeam().name().equals(myTeam)) {
                enemies.add(player);
            }
        }

        return enemies;
    }

    private boolean isValidPosition(Position pos, GameState gameState) {
        Cell[][] map = gameState.getMap();
        int x = pos.getX(), y = pos.getY();

        if (x < 0 || x >= map[0].length || y < 0 || y >= map.length) {
            return false;
        }

        Cell cell = map[y][x];
        String terrain = cell.getTerrain().name();
        return !"I".equals(terrain) && !"N".equals(terrain) && !"D".equals(terrain);
    }
}
